abstract class Worker extends Thread{

	// product for the work-process are taken from the source...
	private Storage source = null;
	// ... and put into the sink
	private Storage sink = null;

	// amount of products needed for 1 work-process
	private int packageSizeConsume = 1;
	
	// amount of product 1 work-process yields
	private int packageSizeProduce = 1;
	
	// counts how often the work-method finished
	protected int workCounter = 0;
	
	// production-time in milliseconds (between the take form a source and the put into a sink)
	private int delay = 10;
	
	// if false, stops the worker
	private boolean isAlive = true;
	
	protected Worker(Storage source, Storage sink){
		this(source, sink, 1, 1, 100);
	}
	
	protected Worker(Storage source, Storage sink, int packageSizeConsume, int packageSizeProduce){
		this(source, sink, packageSizeConsume, packageSizeProduce, 100);
	}
	
	protected Worker(Storage source, Storage sink, int delay){
		this(source, sink, 1, 1, delay);
	}
	
	protected Worker(Storage source, Storage sink, int packageSizeConsume, int packageSizeProduce, int delay){
		this.source = source;
		this.sink = sink;
		this.packageSizeConsume = packageSizeConsume;
		this.packageSizeProduce = packageSizeProduce;
		this.delay = delay;
	}
	
	// this method takes out the needed products from the source, waits and puts the produced goods into the sink
	public void work(){
		
		if(source != null){
			message("i need "+packageSizeConsume+" from "+source);
			source.take(packageSizeConsume);
		}
		
		// simulated workingprocess
		try{
			message("i am producing with resources from "+source+" for "+sink);
			Thread.sleep(delay);
		} catch(Exception e){
			System.out.println("Exception in work(): "+e);
		}
		
		if(sink != null){
			message("i want to put "+packageSizeProduce+" into "+sink);
			sink.put(packageSizeProduce);
		}
		
		workCounter++;
		
	}
	
	protected abstract void message(String msg);
	
	public String toString(){
		return "I worked "+workCounter+" times. One working-process takes me "+delay+" milliseconds. I take "+packageSizeConsume+" product from "+source+", produce "+packageSizeProduce+" products and put them into "+sink;
	}
	
	public void run(){
		while(true){
			work();
			if(!isAlive)
				break;
		}
	}
	
	public synchronized void endWork(){
		isAlive = false;
		notify();
	}
}